package com.pandora.framework.util;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.pandora.common.util.StringUtils;
import com.pandora.common.util.TimeUtils;
import com.pandora.framework.constant.Constants;

/**
 * 日志工具类
 * 
 * @author JingChenglong 2017/12/16 13:25
 *
 */
public class LogUtils {

	public static final String LOG_TYPE_INFO = "INFO";
	public static final String LOG_TYPE_ERROR = "ERROR";

	private static String LOG_PATH = "C:/log/";
	private static String LOG_SUBPATH = "yyyyMMdd/";
	private static String LOG_SUFFIX = ".log";
	private static long LOG_MAXFILESIZE = Constants.MBYTE;
	private static String LOG_CHARSET = Constants.ENCODING_UTF8;

	private static ConcurrentLinkedQueue<String> logQueue = null;

	public static void init() {

		String logMaxFileSize = "";

		LOG_PATH = PropertiesUtils.getLog("LOG_PATH");
		LOG_SUBPATH = PropertiesUtils.getLog("LOG_SUBPATH");
		LOG_SUFFIX = PropertiesUtils.getLog("LOG_SUFFIX");
		logMaxFileSize = PropertiesUtils.getLog("LOG_MAXFILESIZE");
		LOG_CHARSET = PropertiesUtils.getLog("LOG_CHARSET");

		int tempMaxFileSize = 0;
		if (!logMaxFileSize.equalsIgnoreCase(Constants.UNKNOWN) && logMaxFileSize.length() > 2) {
			tempMaxFileSize = StringUtils.nullToIntZero(logMaxFileSize.substring(0, logMaxFileSize.length() - 2));
		}

		if (logMaxFileSize.endsWith("KB")) {
			LOG_MAXFILESIZE = tempMaxFileSize << 10;
		} else if (logMaxFileSize.endsWith("MB")) {
			LOG_MAXFILESIZE = tempMaxFileSize << 20;
		}

		if (logQueue == null) {
			logQueue = new ConcurrentLinkedQueue<String>();
		}

		LogThread logThread = new LogThread();
		logThread.setDaemon(true);// 设置日志记录线程为守护线程
		logThread.start();
	}

	private static class LogThread extends Thread {
		public void run() {
			while (true) {
				if (logQueue != null && !logQueue.isEmpty()) {
					doLog(logQueue.poll());
				} else {
					TimeUtils.sleep(50);
				}
			}
		}
	}

	private static synchronized void doLog(String str) {
		if (StringUtils.isEmpty(str)) {
			return;
		}
		String logPath = LOG_PATH + getSubLogPath();
		File path = new File(logPath);
		if (!path.exists()) {
			path.mkdirs();
		}
		File logFile = new File(logPath + TimeUtils.getDate() + LOG_SUFFIX);
		if (logFile.exists() && logFile.length() >= LOG_MAXFILESIZE) {
			File backLogFile = new File(logPath + TimeUtils.getTimeInt() + LOG_SUFFIX);
			logFile.renameTo(backLogFile);
			if (backLogFile.canWrite()) {
				backLogFile.setWritable(false);
			}
		}

		RandomAccessFile raf = null;

		try {
			if (!logFile.canWrite()) {
				logFile.setWritable(true);
			}

			raf = new RandomAccessFile(logFile, "rwd");
			raf.seek(raf.length());
			raf.write(((TimeUtils.getTime() + "：" + str + "\r\n").getBytes(LOG_CHARSET)));
		} catch (Exception e) {
			printInfo(str);
			printError(StringUtils.nullToStrTrim(e.getMessage()));
		} finally {
			if (raf != null) {
				try {
					raf.close();
				} catch (IOException e) {
					logError(e.getMessage());
				}
				raf = null;
			}
		}
	}

	public static void log(String type, String info) {
		log("[" + type + "]==>" + info);
	}

	public static void log(String type, String code, String info) {
		String message = PropertiesUtils.getMessage(code);
		if (StringUtils.isEmpty(message) || Constants.UNKNOWN.equalsIgnoreCase(message)) {
			message = PropertiesUtils.getBusinessMessage(code);
		}
		log("[" + type + "]==>" + code + "(" + message + ")：" + info);
	}

	public static void logInfo(String info) {
		log(LOG_TYPE_INFO, info);
	}

	public static void logError(String info) {
		log(LOG_TYPE_ERROR, info);
	}

	public static void logError(String code, String info) {
		log(LOG_TYPE_ERROR, code, info);
	}

	public static void log(String info) {
		addQueue(info);
	}

	public static void log(boolean flag, String info) {
		log(flag ? LOG_TYPE_INFO : LOG_TYPE_ERROR, info);
	}

	public static void addQueue(String info) {
		if (logQueue == null) {
			logQueue = new ConcurrentLinkedQueue<String>();
		}
		logQueue.add(info);
	}

	public static void print(String str) {
		System.out.println(TimeUtils.getTime() + " : " + str);
	}

	public static void printInfo(String info) {
		System.out.println("[" + LOG_TYPE_INFO + "]" + TimeUtils.getTime() + " : " + info);
	}

	public static void printError(String error) {
		System.err.println("[" + LOG_TYPE_ERROR + "]" + TimeUtils.getTime() + " : " + error);
	}

	public static String getSubLogPath() {
		return TimeUtils.getSysTime(LOG_SUBPATH);
	}
}